#include "SymbolTable.h"
#include "Module.h"
#include "AST.h"
#include "utils.h"
#include <variant>

class Ret_visit_funcOrVarDef{
public:
    variant<int, float, string> res;
    bool is_funcDef = false;

    Ret_visit_funcOrVarDef(){
        this -> res = 0;
        this -> is_funcDef = false;
    }

    Ret_visit_funcOrVarDef(variant<int, float, string> res, bool is_funcDef){
        this -> res = res;
        this -> is_funcDef = is_funcDef;
    }
};

class Ret_visit_argCompUnit{
public:
    string ident;
    variant<int, float, string> init_val;
    bool is_funcDef = false;

    Ret_visit_argCompUnit(){
        this -> ident = "";
        this -> init_val = 0;
        this -> is_funcDef = false;
    }
    Ret_visit_argCompUnit(string ident, variant<int, float, string> init_val, bool is_funcDef){
        this -> ident = ident;
        this -> init_val = init_val;
        this -> is_funcDef = is_funcDef;
    }
};

string visit_unaryOp(ASTNode* node, SymbolTable* s, BasicBlock* bb);
variant<int, float> visit_number(ASTNode* node, SymbolTable* s, BasicBlock* bb);
variant<int, float, string> visit_primaryExp(ASTNode* node, SymbolTable* s, BasicBlock* bb);
void visit_mulExpAtom(ASTNode* node, SymbolTable* s, BasicBlock* bb);
variant<int, float, string> visit_unaryExp(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
variant<int, float, string> visit_mulExp(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
void visit_addExpAtom(ASTNode* node, SymbolTable* s, BasicBlock* bb);
variant<int, float, string> visit_addExp(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
void visit_relExpAtom(ASTNode* node, SymbolTable* s, BasicBlock* bb);
variant<int, float, string> visit_relExp(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
void visit_eqExpAtom(ASTNode* node, SymbolTable* s, BasicBlock* bb);
variant<int, float, string> visit_eqExp(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
void visit_assignExpAtom(ASTNode* node, SymbolTable* s, BasicBlock* bb);
variant<int, float, string> visit_assignExp(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
variant<int, float, string> visit_exp(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
variant<int, float, string> visit_initVal(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
variant<int, float, string> visit_argVarDef(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
string visit_Ident(ASTNode* node, SymbolTable* s, BasicBlock* bb);
pair<string, variant<int, float, string> > visit_varDef(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
string visit_bType(ASTNode *node, SymbolTable *s, BasicBlock* bb);
void visit_argVarDecl(ASTNode* node, SymbolTable* s, BasicBlock* bb);
Ret_visit_funcOrVarDef* visit_funcOrVarDef(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
Ret_visit_argCompUnit* visit_argCompUnit(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
void visit_compUnit(ASTNode* node, SymbolTable* s, BasicBlock* bb, Module* m);
void visit_Program(ASTNode* node);
void visit_funcDef(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb, string ident, string ret_type);
vector<pair<string, string>> visit_funcFParams(ASTNode* node, SymbolTable* s, BasicBlock* bb);
void visit_block(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
void visit_varDecl(ASTNode *ctx, SymbolTable *s, Module *m, BasicBlock* bb);
void visit_decl(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
void visit_blockItem(ASTNode* node, SymbolTable* s, Module* m, BasicBlock* bb);
void visit_callFunc(ASTNode* node, SymbolTable* s, BasicBlock* bb);